#include "LogicSystem.h"

#include "AsioIOServicePool.h"
#include "HttpConnection.hpp"
#include "Logger.hpp"
#include "MySQLMgr.h"
#include <codecvt>
#include <fstream>
// #include <streambuf>

namespace NS_rt_val
{ // 返回值
struct rt_val
{
    std::string message;
    json data;
};

void to_json(json &j, const rt_val &rt_val)
{
    json tmp;
    tmp["message"] = rt_val.message;
    for (auto &[key, val] : rt_val.data.items())
    {
        tmp[key] = val;
    }
    j = tmp;
}

void from_json(const json &j, rt_val &rt_val)
{
    j.at("message").get_to(rt_val.message);
    json tmp;
    for (auto &[key, val] : j.items())
    {
        if (key != "message")
        {
            tmp[key] = val;
        }
    }
    rt_val.data = tmp;
}

// rt_val myObj;
// auto jv = boost::json::value_from(myObj);
} // namespace NS_rt_val

LogicSystem::LogicSystem()
{
    // 注册各种请求
    RegGet("/get_test", [this](std::shared_ptr<HttpConnection> con) { // 测试get请求
        std::unordered_map<std::string, std::string> params = con->_get_params;
        json j;
        json data;
        std::string msg;
        // 使用nlohmann_json可以很方便地将各种STL容器转换成json
        data["params"] = params;
        msg = "success";

        // 使用nlohmann_json解析库生成json数据返回
        this->common_rtn_data(msg, data, con);
    });

    // shops_data请求
    RegGet("/api/shop/shop_data", [this](std::shared_ptr<HttpConnection> con) {
        json j;
        json data;
        std::string msg;
        // this->readJson("../statics/shop_data.json", data);
        // TODO:数据库并发量还是不够，压力上来了服务器很容易卡住，需要提高并发量
        // 判断参数是否为空，如果是空则查询所有数据，否则根据name来查询
        if (con->_get_params.empty())
            data = MySQLMgr::GetInstance()->getShopDatas();
        else
            data = MySQLMgr::GetInstance()->getShopDatasByName(con->_get_params["name"]);
        if (data.empty())
        {
            // std::cout << "error read in shop_data.json" << std::endl;
            msg = "error read in shop_data";
        }
        else
        {
            msg = "success";
        }
        this->common_rtn_data(msg, data, con);
    });

    // get请求首页信息
    RegGet("/api/food/index", [this](std::shared_ptr<HttpConnection> con) {
        json j;
        json data;
        std::string msg;

        this->readJson("../statics/index.json", data);
        if (data.empty())
        {
            std::cout << "error read in index_data.json" << std::endl;
            msg = "error read in index_data.json";
        }
        else
        {
            msg = "success";
        }
        this->common_rtn_data(msg, data, con);
    });

    // get请求菜单列表
    RegGet("/api/food/list", [this](std::shared_ptr<HttpConnection> con) {
        json j;
        json data;
        std::string msg;
        // 使用RAII技术防止由于发生异常而不能发送数据
        this->readJson("../statics/list.json", data);
        if (data.empty())
        {
            std::cout << "error read in list.json" << std::endl;
            msg = "error read in list.json";
        }
        else
        {
            msg = "success";
        }
        this->common_rtn_data(msg, data, con);
    });

    // get请求订单列表
    RegGet("/api/food/orderlist", [this](std::shared_ptr<HttpConnection> con) {
        json j;
        json data;
        std::string msg;
        std::string filename = "../statics/orderlist-0.json";

        if (con->_get_params["last_id"] == "10")
        {
            filename = "../statics/orderlist-10.json";
            std::cout << "filename is " << filename << std::endl;
        }
        else if (con->_get_params["last_id"] == "20")
        {
            filename = "../statics/orderlist-20.json";
            std::cout << "filename is " << filename << std::endl;
        }

        this->readJson(filename, data);
        if (data.empty())
        {
            std::cout << "error read in list.json" << std::endl;
            msg = "error read in list.json!";
        }
        else
        {
            msg = "success";
        }
        this->common_rtn_data(msg, data, con);
    });

    // 获取静态资源
    RegGet("/static", [this](std::shared_ptr<HttpConnection> con) {
        // TODO:就算没有请求体也会读取出\r\n\r\n来，需要去掉
        std::string filename = con->_get_params["res_path"];
        LOG_INFO("filename is {}", filename);
        std::string path = "../statics/" + filename;
        int len = 0;
        std::string msg;
        if (filename.find(".png") != std::string::npos) // 如果是图片
        {
            // char data[8192]; // 可以处理M以下的文件
            std::size_t len = this->deal_img(path, _buffer, con);
            // if (data.empty())
            // {
            //     LOG_ERROR("data is nullptr!");
            //     return;
            // }
            msg = "success";
            this->common_rtn_img(msg, _buffer, len, con);
        }
        else if (filename.find(".json") != std::string::npos) // 如果是js文件
        {
            std::string data;
            std::weak_ptr<HttpConnection> weak_con(con);
            Defer defer([this, weak_con, &data]() {
                auto ptr = weak_con.lock();
                // std::copy(data.begin(), data.end(), con->_response.body());
                ptr->_response.set_body(data);
                // beast::ostream(con->_response.body()) << data;
            });

            std::ifstream file(path, std::ios::in);
            json jv;
            try
            {
                if (file.is_open())
                {
                    jv << file;
                    data = jv.dump();
                }
                else
                {
                    LOG_ERROR("open file failed, file is not exists!");
                }
                file.close();
            }
            catch (const std::exception &e)
            {
                LOG_ERROR("read json failed:\n->{}", e.what());
                file.close();
            }
        }
        else if (filename.find(".txt") != std::string::npos)
        {
            std::weak_ptr<HttpConnection> weak_con(con);
            std::string data;
            Defer defer([this, weak_con, &data]() {
                auto ptr = weak_con.lock();
                // beast::ostream(con->_response.body()) << data;
                std::copy(data.begin(), data.end(), ptr->_response.body());
            });
            std::ifstream file(path, std::ios::in);
            std::string buf;

            try
            {
                if (file.is_open())
                {
                    while (getline(file, buf))
                    {
                        data += buf + "\n";
                        // file >> data;
                    }
                }
                else
                {
                    LOG_ERROR("open file failed, file is not exists!");
                }
                file.close();
            }
            catch (const std::exception &e)
            {
                LOG_ERROR("read json failed:\n->{}", e.what());
                file.close();
            }
        }
    });
}

bool LogicSystem::HandleGetReq(std::string url, std::shared_ptr<HttpConnection> con)
{

    if (_get_handlers.find(url) == _get_handlers.end())
        return false;
    _get_handlers[url](con);
    return true;
}

bool LogicSystem::HandlePostReq(std::string url, std::shared_ptr<HttpConnection> con)
{
    if (_post_handlers.find(url) == _post_handlers.end())
        return false;
    _post_handlers[url](con);
    return true;
}

void LogicSystem::RegGet(std::string url, HttpHandler handler)
{
    _get_handlers[url] = handler;
}

void LogicSystem::RegPost(std::string url, HttpHandler handler)
{
    _post_handlers[url] = handler;
}

void LogicSystem::readJson(const std::string path, json &jv)
{
    std::fstream file(path);
    try
    {
        if (file.is_open())
        {
            file >> jv;
            std::cout << jv << std::endl;
        }
        else
        {
            std::cout << "file: " << path << " open failed!" << std::endl;
        }
        file.close();
    }
    catch (json::exception &e)
    {
        // std::cerr << e.what() << std::endl;
        LOG_ERROR("read json failed:\n->{}", e.what());
        file.close();
    }
}

void LogicSystem::common_rtn_data(std::string message, json &data, std::shared_ptr<HttpConnection> con)
{
    // std::string target = con->_request.target();
    // 使用RAII技术防止由于发生异常而不能发送数据
    json j;
    std::weak_ptr<HttpConnection> weak_con(con);
    Defer df([&j, weak_con]() {
        auto ptr = weak_con.lock();
        std::string jv = j.dump();
        // std::copy(jv.begin(), jv.end(), con->_response.body());
        ptr->_response.set_body(jv);
        // beast::ostream(con->_response.body()) << j.dump();
        return;
    });
    NS_rt_val::rt_val rtval;
    try
    {
        con->_response.content_type("application/json");
        con->_response.accept_charset("utf-8");
        rtval = {message, data};
        j = rtval;
        // std::cout << "------------------------: " << j << std::endl;
    }
    catch (const std::exception &e)
    {
        // std::cerr << e.what() << '\n';
        LOG_ERROR("common_rtn_data failed:\n->{}", e.what());
    }
}

void LogicSystem::common_rtn_img(std::string message, char *data, std::size_t len, std::shared_ptr<HttpConnection> con)
{
    con->_response.content_type("image/png");
    con->_response.accept_ranges("bytes");
    if (data == nullptr)
    {
        LOG_WARN("data is empty!");
        return;
    }
    std::weak_ptr<HttpConnection> weak_con(con);
    // Defer df([&data, &len, weak_con]() {
        auto ptr = weak_con.lock();
        // TODO:实现二进制数据的响应
        // con->_response.body() = *data;
        // memcpy(con->_response.body(), data, len);
        ptr->_response.set_img_body(data, len);
    // });
}

// #include <Windows.h>
#include <boost/asio/stream_file.hpp>
std::size_t LogicSystem::deal_img(std::string &img_path, char *data, std::shared_ptr<HttpConnection> con)
{
    std::ifstream file;
    //TODO:使用缓存读取图片, 以后就按照这个内容进行修改
    // char buffer[1024];      //缓冲
    // std::string content;    //图片数据
    // file.open(img_path, std::ios::binary | std::ifstream::in);
    // if (file.is_open())
    // {
    //     while (!file.eof())
    //     {
    //         file.read(buffer, 1024);
    //         content.append(buffer, 1024);   //每次追加到content里面，读取完毕后content内容就是图片数据
    //         memset(buffer, 0, 1024);
    //     }
    // }
    


    try
    {
        // file.open(img_path, std::ios::binary | std::ifstream::in);
        /* code */
        if (std::filesystem::exists(img_path))
        {
            // if (file.is_open())

            // {
                // file.seekg(0, std::ios::end);
                // auto len = file.tellg();
                // file.seekg(0, std::ios::beg);
                // // 读取图片
                // file.read(data, len);
                // 使用asio来异步读取
                //  boost::asio::basic_streambuf<char> buf;
            // boost::asio::mutable_buffer buf(data, 1024);
            boost::asio::stream_file file2(AsioIOServicePool::GetInstance()->GetIOService(), img_path,
                                            boost::asio::stream_file::read_only);
            if (file2.is_open())
            {
                auto len = file2.size();
                // std::size_t bytes_read; //已读长度
                async_read_file(file2, data, con->_bytes_read, len, con); // 异步读取

                // int count=0;
                // char c;
                // while (count < len)
                // {
                //     c = file.get();
                //     data[count++] = c;
                // }

                // std::string content(std::istream_iterator<char>(file), std::istream_iterator<char>());
                // std::cout << "content: " << content << std::endl;
                // std::cout << "the acctually count: " << file.gcount() << std::endl;
                // std::cout << "the acctually end: " << file.tellg() << std::endl;
                // boost::asio::read(file, boost::asio::buffer(*data));

                // 读取整个文件内容到缓冲区
                // buffer = {std::istreambuf_iterator<char>(file), {}};
                return len;
            }
            else
            {
                LOG_ERROR("open file failed, file is not exists!");
                data = nullptr;
                return 0;
            }
        }
        else
        {
            LOG_WARN("file: {} is not exists!", img_path);
            data = nullptr;
            return 0;
        }
    }
    catch (const std::exception &e)
    {
        LOG_ERROR("read img failed, ptr may be null:\n\t->{}", e.what());
        file.close();
        return 0;
    }
}

void LogicSystem::async_read_file(asio::stream_file &file, char *buffer, std::size_t &bytes_read,
                                  const std::size_t total_len, std::shared_ptr<HttpConnection> con)
{
    // while(!con->_is_data_ready)
    // {
    //     con->_cv.wait(lk);
    //     bytes_read = 0;
    // }
    std::unique_lock<std::mutex> lk(con->_mtx);
    std::weak_ptr<HttpConnection> weak_con(con);
    con->_cv.wait(lk, [weak_con, &bytes_read](){
        auto con = weak_con.lock();
        bytes_read = 0;     //每次被唤醒时先清空bytes_read
        return !con->_is_data_ready;// 缓存区是否已经准备好可以写入了
    });
    if (con->_is_data_ready)
        con->_cv.notify_one();

    std::cout << "----------buffer is:-----------:\n" << sizeof(buffer) << std::endl;
    asio::mutable_buffer buf(buffer, 1024);
    // std::weak_ptr<HttpConnection> weak_con(con);

    //TODO:上次是在这里报错了
    try
    {
        file.async_read_some(buf, [weak_con, &bytes_read, total_len, &file, buffer, this]
            (boost::system::error_code ec, std::size_t bytes_transferred) {
            auto ptr = weak_con.lock();
            // std::unique_lock<std::mutex> lk(ptr->_mtx);
            // ptr->_cv.wait(lk, [&bytes_read, weak_con]() {
            //     auto ptr = weak_con.lock();
            //     bytes_read = 0;     //每次被唤醒时先清空bytes_read
            //     return !ptr->_is_data_ready;// 缓存区是否已经准备好可以写入了
            // });
            bytes_read += bytes_transferred;
            if (ec)
            {
                // std::cout << "read file failed!" << std::endl;
                LOG_ERROR("read file failed:\n\t->{}", ec.what());
                // lk.unlock();
                ptr->_is_data_ready = true;
                ptr->_cv.notify_one();
                return;
            }
            else
            {
                LOG_INFO("read file success!");
                // stream_buf.commit(bytes_transferred);
                //TODO:total_len的值会莫名其妙地变化
                if (bytes_read < total_len)
                {
                    if (bytes_read >= 1024) // 如果缓冲区已满，则让给响应处理那边读取
                    {
                        // lk.unlock();
                        ptr->_is_data_ready = true;
                        ptr->_cv.notify_one();
                    }
                    async_read_file(file, buffer, /* stream_buf, */ bytes_read, total_len, weak_con.lock());
                }
                else
                {
                    // 已读取完毕
                    std::cout << "read file success!" << std::endl;
                    if (!ptr->_response._is_img)
                    {
                        buffer[total_len] = '\0';
                        std::cout << buffer << std::endl;
                    }
                    // lk.unlock();
                    ptr->_is_data_ready = true;
                    ptr->_cv.notify_one();
                    file.close();
                }
            }
        });
    }
    catch(const std::exception& e)
    {
        LOG_ERROR("async_read_file failed:\n\t->{}", e.what());
    }
    
}